package com.sanri.tools.modules.mock.l7.http.filter;

import com.sanri.tools.modules.core.exception.ToolException;
import com.sanri.tools.modules.core.utils.ServletUtil;
import com.sanri.tools.modules.mock.l7.http.service.LogService;
import com.sanri.tools.modules.mock.l7.http.service.ResponseHandlerManagerService;
import com.sanri.tools.modules.mock.l7.http.service.dtos.RequestLogDto;
import com.sanri.tools.modules.mock.l7.http.service.dtos.ResponseConfig;
import com.sanri.tools.modules.mock.l7.http.service.dtos.UrlBindAndResponseConfig;
import com.sanri.tools.modules.mock.l7.http.service.dtos.UrlBindResponseDto;
import com.sanri.tools.modules.mock.l7.http.service.interceptors.CallInterceptorClient;
import lombok.Cleanup;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class MockHandler {

    @Autowired
    private ResponseHandlerManagerService responseHandlerManagerService;

    @Autowired
    private CallInterceptorClient callInterceptorClient;

    @Autowired
    private LogService logService;

    /**
     * 处理url
     *
     * @param request url
     * @return 处理过的URL
     */
    public String getProcessedUrl(HttpServletRequest request) {
        // get request url path
        String requestUrl = request.getRequestURI();
        //去除前缀(contextPatn)
        if (requestUrl.startsWith("/vmock")){
            requestUrl = StringUtils.substring(requestUrl, 6);
        }

        // 空的话匹配 [/]
        requestUrl = StringUtils.isBlank(requestUrl) ? "/" : requestUrl;
        return requestUrl;
    }

    /**
     * 主执行方法
     * @param request
     * @param response
     */
    @SneakyThrows
    public void main(HttpServletRequest request, HttpServletResponse response)  {
        // set utf8
        response.setCharacterEncoding("utf-8");
        String requestUrl = getProcessedUrl(request);

        // 这段话放在 response write close 之后会报错, 不知道为啥
        @Cleanup BufferedReader reader = request.getReader();
        String body = reader.lines().collect(Collectors.joining(System.lineSeparator()));

        // 根据 requestUrl 获取一个响应数据配置
        final UrlBindAndResponseConfig urlBindAndResponseConfig = responseHandlerManagerService.choseResponse(requestUrl);
        final ResponseConfig responseConfig = urlBindAndResponseConfig.getResponseConfig();

        final ResponseConfig.ResponseDetail http = responseConfig.getResponseDetail();

        final String method = http.getMethod();
        if (!request.getMethod().equals(method)){
            throw new ToolException("不支持的调用方法, 仅支持: "+ http.getMethod());
        }

        // callInterceptorClient 可以动态设置, 根据不同的业务, 设置不同的客户端, 使用不同的拦截器链;  当前默认是使用完整的拦截器链
        final UrlBindResponseDto urlBindResponseDto = urlBindAndResponseConfig.getUrlBindResponseDto();
        final RequestLogDto requestLogDto = new RequestLogDto(urlBindResponseDto, responseConfig.getResponseDetail());
        requestLogDto.getTimeInfo().setBegin(new Date());
        requestLogDto.setHitUrl(requestUrl);
        requestLogDto.setIp(ServletUtil.getClientIP(request));
        try {
            // 执行拦截器, 可以在拦截器中修改 body;  如果做加密等相关
            callInterceptorClient.main(request, response, responseConfig);
            requestLogDto.getTimeInfo().setEnd(new Date());
        }catch (Exception e){
            log.error("执行异常, 原因为: {}",e.getMessage(),e);
            requestLogDto.getTimeInfo().setEnd(new Date());
            requestLogDto.setErrorMsg(e.getMessage());
        }

        try {
            // 获取请求信息
            List<ResponseConfig.NameValuePair> headers = new ArrayList<>();
            final Enumeration<String> headerNames = request.getHeaderNames();
            while (headerNames.hasMoreElements()){
                final String key = headerNames.nextElement();
                headers.add(new ResponseConfig.NameValuePair(key, request.getHeader(key)));
            }
            final String queryString = request.getQueryString();

            RequestLogDto.RequestDetail requestDetail = new RequestLogDto.RequestDetail(queryString, headers, body);
            requestLogDto.setRequestDetail(requestDetail);

            logService.recordLog(requestLogDto);
        }catch (IOException e){
            log.error("记录请求日志时出错: {}",e.getMessage(), e);
        }
    }
}
